﻿using System;
using System.ComponentModel;
using System.Globalization;
using System.Net;
using System.Reflection;
using System.ServiceModel.DomainServices.Client.ApplicationServices;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using RIBA.Helper;
using Riba.MVVMSL;
using RIBA.Web;

namespace RIBA
{
	public class MainPage_VM : ViewModelBase
	{
		private Assembly _adminAssembly;
		private Type _currentPageType;

		public RelayCommand CommandMenu { get; set; }
		public RelayCommand CommandLogin { get; set; }
		public RelayCommand CommandLanguage { get; set; }

		public string Version
		{
			get
			{
				var assembly = Assembly.GetExecutingAssembly();
				var name = new AssemblyName(assembly.FullName);
				return "RIBA Version " + name.Version.ToString(3);
			}
		}

		private string _status = "";
		public string Status
		{
			get { return _status; }
			set { SetPropertyValue(ref _status, value, () => Status); }
		}

		private bool _isAuthenticated;
		public bool IsAuthenticated
		{
			get { return _isAuthenticated; }
			set
			{
				SetPropertyValue(ref _isAuthenticated, value, () => IsAuthenticated);
				RaisePropertyChanged(() => LoginButtonText);
				RaisePropertyChanged(() => Roles);
				RaisePropertyChanged(() => IsAdmin);
			}
		}

		public bool IsAdmin
		{
			get
			{
				return WebContext.Current.User.IsInRole("admin");
			}
		}

		public string Roles
		{
			get
			{
				if (WebContext.Current.User.Roles == null)
					return "";

				var s = "";
				foreach (var role in WebContext.Current.User.Roles)
				{
					s += role;
					s += " ";
				}
				return s;
			}
		}

		public string LoginButtonText
		{
			get
			{
				if (IsAuthenticated)
					return TextRes.Logout;
				return TextRes.Login;
			}
		}

		private string _currentLanguage;
		public string CurrentLanguage
		{
			get { return _currentLanguage; }
			set { SetPropertyValue(ref _currentLanguage, value, () => CurrentLanguage); }
		}

		private string _counter = "";
		public string Counter
		{
			get { return _counter; }
			set { SetPropertyValue(ref _counter, value, () => Counter); }
		}

		private DispatcherTimer _dispatcherTimer;

		private readonly DomainServices.IDomainServiceRIBA _domainService;

		public MainPage_VM(DomainServices.IDomainServiceRIBA domainService)
		{
			_domainService = domainService;

			CurrentLanguage = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName;

			if (!DesignerProperties.IsInDesignTool) //WebContext.Current != null
			{
				WebContext.Current.Authentication.LoggedIn += Authentication_LoggedIn;
				WebContext.Current.Authentication.LoggedOut += Authentication_LoggedOut;
			}

			CommandMenu = new RelayCommand
				(
					cmdPar =>
					{
						IsBusy = true;

						if (cmdPar.ToString() == "GetLongAnswer")
						{
							var p = new NavigateToViewEventArgs(null);
							RaiseNavigateToView(p);

							Status = TextRes.GetLongAnswer;

							_domainService.GetLongAnswer(10480, GetLongAnswer_Callback);
						}

						else if (cmdPar.ToString() == "AdminOnly")
						{
							Status = "";
							IsBusy = false;

							if (_currentPageType != null && _currentPageType.FullName != null)
							{
								_currentPageType = 
									_adminAssembly.GetType(_currentPageType.FullName.Contains("AdminPage1") ? 
											"Admin.AdminPage2" : "Admin.AdminPage1");

								var p = new NavigateToViewEventArgs(_currentPageType, AnimationMode.Forward);
								RaiseNavigateToView(p);
							}
							else
							{
								if (Application.Current.Host.Source == null)
								{
									RaiseShowMsgBox(new ShowMsgBoxEventArgs("Application.Current.Host.Source == null", "MainPage_VM.AdminOnly"));
									return;
								}

								var uri = Application.Current.Host.Source.AbsoluteUri;
								var i = uri.IndexOf("/ClientBin");

								//Admin.dll is renamed to Admin.txt, because I could not get mime-type .dll working on my providers webserver
								//uri = uri.Substring(0, i) + string.Format("/ClientBin/secure/{0}.txt", "Admin"); //xap, dll  TODO

								uri = uri.Substring(0, i) + string.Format("/DllHandler.ashx?dll={0}", "Admin");

								//RaiseShowMsgBox(new ShowMsgBoxEventArgs(uri, "MainPage_VM.AdminOnly"));

								var webClient = new WebClient();
								webClient.OpenReadCompleted += webClient_OpenReadCompleted;
								webClient.OpenReadAsync(new Uri(uri));
							}
						}

						else
						{
							var p = new NavigateToViewEventArgs(null);
							RaiseNavigateToView(p);

							Status = TextRes.QueryServerTime;

							_dispatcherTimer = new DispatcherTimer();
							_dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
							_dispatcherTimer.Tick += OnTick;
							_dispatcherTimer.Start();

							_domainService.GetServerTime(cmdPar.ToString(), GetServerTime_Callback);
						}
					}
				) { IsEnabled = true };

			CommandLogin = new RelayCommand
				(
					cmdPar =>
					{
						if (DesignerProperties.IsInDesignTool) //WebContext.Current != null
							return;
						if (WebContext.Current.Authentication.IsBusy)
							return;

						if (!WebContext.Current.User.IsAuthenticated)
						{
							var args = new LoadChildWindowEventArgs(typeof(Login), null, null);

							RaiseLoadChildWindow(args);
						}
						else
						{
							var p = new NavigateToViewEventArgs(null);
							RaiseNavigateToView(p);

							WebContext.Current.Authentication.Logout(false);
						}
					}
				) { IsEnabled = true };

			CommandLanguage = new RelayCommand
				(
					cmdPar =>
					{
						string twoLetterIsoLanguageName = cmdPar.ToString();

						//<SupportedCultures>de;en;fr</SupportedCultures> im Projektfile !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

						Thread.CurrentThread.CurrentCulture = new CultureInfo(twoLetterIsoLanguageName);
						Thread.CurrentThread.CurrentUICulture = new CultureInfo(twoLetterIsoLanguageName);

						CurrentLanguage = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName;

						TextRes.SetLanguage(CurrentLanguage);
						((TextResWrapper)Application.Current.Resources["App_TextResourceWrapper"]).OnPropertyChanged(new PropertyChangedEventArgs("TextResource"));

						RaisePropertyChanged(() => LoginButtonText);
						RaisePropertyChanged(() => Roles);
						RaisePropertyChanged(() => IsAdmin);
					}
				) { IsEnabled = true };
		}

		void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
		{
			if (e.Error == null)
			{
				//RaiseShowMsgBox(new ShowMsgBoxEventArgs(e.ToString(), "webClient_OpenReadCompleted"));

				var assemblyPart = new AssemblyPart();
				_adminAssembly = assemblyPart.Load(e.Result);
				if (_adminAssembly == null)
				{
					RaiseShowMsgBox(new ShowMsgBoxEventArgs("assembly=null", "webClient_OpenReadCompleted"));
					return;
				}

				RaiseShowMsgBox(new ShowMsgBoxEventArgs(TextRes.ExternalAssemblyLoaded, "webClient_OpenReadCompleted"));

				//A error 4004 (File not found) is thrown, if types in the assembly are accessed inside
				//_OpenReadCompleted because CRL does not find type 'Admin' in the current application domain yet

				_currentPageType = _adminAssembly.GetType("Admin.AdminPage1");
				if (_currentPageType == null)
				{
					RaiseShowMsgBox(new ShowMsgBoxEventArgs("type=null", "webClient_OpenReadCompleted"));
					return;
				}

				var p = new NavigateToViewEventArgs(_currentPageType, AnimationMode.Forward);
				RaiseNavigateToView(p);
			}
			else
			{
				RaiseShowMsgBox(new ShowMsgBoxEventArgs(e.Error.Message, "webClient_OpenReadCompleted"));
				if (e.Error.InnerException != null)
					RaiseShowMsgBox(new ShowMsgBoxEventArgs(e.Error.InnerException.Message, "webClient_OpenReadCompleted"));
			}
		}

		private void OnTick(object sender, EventArgs e)
		{
			int i;
			if (int.TryParse(Counter, out i))
				i++;
			else
				i = 1;
			Counter = i.ToString();
		}

		void Authentication_LoggedIn(object sender, AuthenticationEventArgs e)
		{
			IsAuthenticated = e.User.Identity.IsAuthenticated;
		}

		void Authentication_LoggedOut(object sender, AuthenticationEventArgs e)
		{
			IsAuthenticated = e.User.Identity.IsAuthenticated;
		}

		private void GetServerTime_Callback(string time, Exception exception)
		{
			_dispatcherTimer.Stop();
			_dispatcherTimer = null;
			Counter = "";

			Status = "";
			IsBusy = false;

			if (exception != null)
			{
				Common.RaiseShowMessageWindow(this, exception.Message, "GetServerTime_Callback");
				return;
			}

			Common.RaiseShowMessageWindow(this, time, "GetServerTime_Callback");
		}

		private void GetLongAnswer_Callback(string answer, Exception exception)
		{
			Status = "";
			IsBusy = false;

			if (exception != null)
			{
				Common.RaiseShowMessageWindow(this, exception.Message, "GetLongAnswer_Callback");
				return;
			}

			Common.RaiseShowMessageWindow(this, string.Format("{0} Zeichen", answer.Length), "GetLongAnswer_Callback");
		}
	}
}